package pers.hl.module_main.admin.lib

import android.Manifest
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
import android.view.Gravity
import android.view.MotionEvent
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import com.amap.api.maps2d.*
import com.amap.api.maps2d.AMap.OnMarkerClickListener
import com.amap.api.maps2d.model.LatLng
import com.amap.api.maps2d.model.MyLocationStyle
import com.amap.api.services.core.LatLonPoint
import com.amap.api.services.geocoder.GeocodeResult
import com.amap.api.services.geocoder.GeocodeSearch
import com.amap.api.services.geocoder.RegeocodeResult
import com.blankj.utilcode.util.LogUtils
import com.chad.library.adapter.base.listener.OnItemClickListener
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.permissionx.guolindev.PermissionX
import com.yanzhenjie.recyclerview.SwipeMenuCreator
import com.yanzhenjie.recyclerview.SwipeMenuItem
import per.goweii.anylayer.DialogLayer
import pers.hl.common.base.BaseVBVMActivity
import pers.hl.common.base.ext.showMessage
import pers.hl.common.ui.CommonTextWatcher
import pers.hl.lib_global.common.AMapUtils
import pers.hl.lib_global.common.Const
import pers.hl.lib_global.model.bean.Library
import pers.hl.module_main.CommonEditActivity
import pers.hl.module_main.R
import pers.hl.module_main.common.BaseLibQuickAdapter
import pers.hl.module_main.common.ConfirmDialog
import pers.hl.module_main.common.PageHelper
import pers.hl.module_main.common.SwipeMenuHelper
import pers.hl.module_main.databinding.ActivityLibManageBinding


class LibManageActivity : BaseVBVMActivity<ActivityLibManageBinding, LibManageViewModel>(),
    AMap.OnMapTouchListener {

    private lateinit var libAdapter: BaseLibQuickAdapter<Library, BaseViewHolder>

    /**
     * 当前位置（经纬度信息）
     */
    private var curLatLng = LatLng(0.0, 0.0)

    // 中心点跟随移动
    private var followMove = false

    private lateinit var mUiSettings: UiSettings
    private lateinit var aMap: AMap
    private lateinit var mapView: MapView

    override fun initView(savedInstanceState: Bundle?) {
        initAMap(savedInstanceState)
        initTitle()
        initSearchBar()
        initRv()
    }

    private fun initAMap(savedInstanceState: Bundle?) {
        initMapView(savedInstanceState)
        initMapSettings()
        initMapListener()
    }

    private fun initMapSettings() {
        // 控件是指浮在地图图面上的一系列用于操作地图的组件，例如缩放按钮、指南针、定位按钮、比例尺等。
        // UiSettings 类用于操控这些控件，以定制自己想要的视图效果 api查看:https://lbs.amap.com/api/android-sdk/guide/interaction-with-map/control-interaction/
        mUiSettings = aMap.uiSettings
        // 隐藏缩放按钮
        mUiSettings.isZoomControlsEnabled = false
        // 隐藏定位按钮
        mUiSettings.isMyLocationButtonEnabled = false
        // 可触发定位并显示当前位置
        //        aMap.setMyLocationEnabled(true);
        // 比例尺控件
        mUiSettings.isScaleControlsEnabled = true
    }

    private fun initMapView(savedInstanceState: Bundle?) {
        mapView = mBinding.mapView
        mapView.onCreate(savedInstanceState)
        lifecycle.addObserver(AMapLifecycleObserver(mapView))
        aMap = mapView.map
        requestPermission()
    }

    private fun initMapListener() {
        // 地图点击监听
        aMap.setOnMapClickListener {
            LogUtils.d("点击地图：当前位置{${it.longitude}, ${it.latitude}}")
            AMapUtils.transPositionToAddress(
                this,
                LatLonPoint(it.latitude, it.longitude),
                object : GeocodeSearch.OnGeocodeSearchListener {
                    override fun onRegeocodeSearched(result: RegeocodeResult?, code: Int) {
                        if (code != 1000) {
                            LogUtils.e(TAG, "坐标转换位置失败")
                            return
                        }
                        result?.apply {
                            val city = regeocodeAddress.city
                            val location = regeocodeAddress.formatAddress
                            val option =
                                AMapUtils.getMarkerOption(it, city, location, R.drawable.ic_marker)
                            aMap.addMarker(option)
                        }
                    }

                    override fun onGeocodeSearched(result: GeocodeResult?, code: Int) {

                    }
                })
        }

        // 定义 Marker 点击事件监听
        val markerClickListener = OnMarkerClickListener { marker ->
            // marker 对象被点击时回调的接口
            // 返回 true 则表示接口已响应事件，否则返回false
            val position = marker.position
            val location = marker.snippet
            // 弹框提示，是否添加该位置
            val confirmAddDialog = ConfirmDialog.create(this)
                .content("确定要在此位置添加图书馆？\n【${location}】")
                .setConfirmListener {
                    val library = Library(-1, position.latitude, position.longitude, location, "")
                    showAddLibDialog(library)
                }
                .setCancelListener {
                    marker.remove()
                }
            val latLng = LatLng(position.latitude, position.longitude)
            var existLib = false
            libAdapter.data.forEach {
                if (latLng == LatLng(it.libLatitude, it.libLongitude)) {
                    existLib = true
                }
            }
            if (!existLib) {
                confirmAddDialog.show()
            }
            false
        }
        // 绑定 Marker 被点击事件
        aMap.setOnMarkerClickListener(markerClickListener)
    }

    /**
     * 添加图书馆提示框
     */
    private fun showAddLibDialog(library: Library) {
        val dialog = DialogLayer(this)
            .contentView(R.layout.layout_input_dialog)
            .cancelableOnTouchOutside(true)
            .backgroundDimAmount(0.5f)
            .gravity(Gravity.CENTER)
            .bindData { layer ->
                layer.apply {
                    val etContent = getView<EditText>(R.id.etContent)
                    val tvConfirm = getView<TextView>(R.id.tvConfirm)
                    val tvCancel = getView<TextView>(R.id.tvCancel)
                    tvConfirm.setOnClickListener {
                        dismiss()
                        val libName = etContent.text.toString()
                        if (TextUtils.isEmpty(libName)) {
                            showMessage("请输入图书馆名称")
                            return@setOnClickListener
                        }
                        library.libName = libName
                        mViewModel.addLibrary(library)
                            .observe(this@LibManageActivity, Observer {
                                showMessage("图书馆添加成功")
                                libAdapter.addData(it)
                            })
                    }
                    tvCancel.setOnClickListener {
                        dismiss()
                    }
                }
            }
        dialog.show()
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        mBinding.mapView.onSaveInstanceState(outState)
    }

    private fun initTitle() {
        mBinding.apply {
            titleBar.clTitle.setBackgroundColor(
                ContextCompat.getColor(
                    this@LibManageActivity,
                    R.color.recommend
                )
            )
            titleBar.tvBarTitle.text = "图书馆管理"
            titleBar.ivBarLeft.setOnClickListener {
                finish()
            }
        }
    }

    private fun initSearchBar() {
        mBinding.apply {
            etSearch.imeOptions = EditorInfo.IME_ACTION_SEARCH
            etSearch.addTextChangedListener(object : CommonTextWatcher(etSearch) {
                override fun textChanged(view: EditText, text: String) {

                }
            })
            etSearch.setOnEditorActionListener { v, actionId, event ->
                if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                    doSearch(etSearch.text.toString())
                }
                false
            }
            etSearch.addTextChangedListener(object : CommonTextWatcher(etSearch) {
                override fun textChanged(view: EditText, text: String) {
                    if (TextUtils.isEmpty(text)) {
                        getAll()
                    }
                }

            })
        }
    }

    /**
     * 名称或位置搜索
     */
    private fun doSearch(keyword: String) {
        if (TextUtils.isEmpty(keyword)) {
            showMessage("请输入内容搜索")
            return
        }
        mViewModel.searchLibrary(keyword).observe(this, Observer {
            libAdapter.setList(it)
        })
    }

    private fun initRv() {
        mBinding.apply {
            rvLib.layoutManager = LinearLayoutManager(this@LibManageActivity)
            libAdapter = object :
                BaseLibQuickAdapter<Library, BaseViewHolder>(R.layout.item_rv_library) {
                override fun convert(holder: BaseViewHolder, item: Library) {
                    holder.getView<ImageView>(R.id.ivLib).setImageResource(R.drawable.ic_library)
                    holder.getView<TextView>(R.id.tvLibName).text = item.libName
                    holder.getView<TextView>(R.id.tvLocation).text = item.libLocation
                }
            }
            rvLib.apply {
                // 创建侧滑菜单
                val menuCreator = SwipeMenuHelper.createDeleteItem(this@LibManageActivity)
                setSwipeMenuCreator(menuCreator)
                setOnItemMenuClickListener { menuBridge, adapterPosition ->
                    // 任何操作必须先关闭菜单，否则可能出现Item菜单打开状态错乱。
                    menuBridge.closeMenu()
                    val deleteItem = libAdapter.getItem(adapterPosition)
                    val libId = deleteItem.libId
                    if (libId == null || libId <= 0) {
                        showMessage("数据错误，请尝试重新进入页面")
                        return@setOnItemMenuClickListener
                    }
                    mViewModel.deleteLibrary(libId).observe(this@LibManageActivity, Observer {
                        getAll()
                    })
                }
                adapter = libAdapter
            }
            libAdapter.setOnItemClickListener(OnItemClickListener { adapter, view, position ->
                val data = adapter.getItem(position) as Library
                editLibDialog(data)
            })
        }
    }

    /**
     * 编辑图书信息
     */
    private fun editLibDialog(data: Library?) {
        if (data == null) {
            showMessage("数据错误")
            return
        }
        PageHelper.navToCommonEditPage(this, data, CommonEditActivity.RC_LIB_MANAGE, CommonEditActivity.TYPE_LIB_MANAGE)
    }

    override fun initData(savedInstanceState: Bundle?) {
        getAll()
    }

    private fun getAll() {
        mViewModel.getAllLibraries().observe(this, Observer { list ->
            libAdapter.setList(list)
            list.forEach {
                val option = AMapUtils.getMarkerOption(
                    LatLng(it.libLatitude, it.libLongitude),
                    it.libName.toString(),
                    it.libLocation.toString(),
                    R.drawable.ic_marker
                )
                aMap.addMarker(option)
            }
        })
    }

    /**
     * 定位
     * myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_SHOW);//只定位一次。
     * myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATE) ;//定位一次，且将视角移动到地图中心点。
     * myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_FOLLOW) ;//连续定位、且将视角移动到地图中心点，定位蓝点跟随设备移动。（1秒1次定位）
     * myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_MAP_ROTATE);//连续定位、且将视角移动到地图中心点，地图依照设备方向旋转，定位点会跟随设备移动。（1秒1次定位）
     * myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE);//连续定位、且将视角移动到地图中心点，定位点依照设备方向旋转，并且会跟随设备移动。（1秒1次定位）默认执行此种模式。
     * //以下三种模式从5.1.0版本开始提供
     * myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER);//连续定位、蓝点不会移动到地图中心点，定位点依照设备方向旋转，并且蓝点会跟随设备移动。
     * myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_FOLLOW_NO_CENTER);//连续定位、蓝点不会移动到地图中心点，并且蓝点会跟随设备移动。
     * myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_MAP_ROTATE_NO_CENTER);//连续定位、蓝点不会移动到地图中心点，地图依照设备方向旋转，并且蓝点会跟随设备移动。
     */
    private fun locate() {
        aMap.isMyLocationEnabled = false // 可触发定位并显示当前位置
        // 实现定位蓝点
        val myLocationStyle =
            MyLocationStyle() //初始化定位蓝点样式类myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE);//连续定位、且将视角移动到地图中心点，定位点依照设备方向旋转，并且会跟随设备移动。（1秒1次定位）如果不设置myLocationType，默认也会执行此种模式。
        myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_FOLLOW_NO_CENTER)
        myLocationStyle.interval(3000) //设置连续定位模式下的定位间隔，只在连续定位模式下生效，单次定位模式下不会生效。单位为毫秒。
        aMap.setMyLocationStyle(myLocationStyle) // 设置定位蓝点的Style
        aMap.uiSettings.isMyLocationButtonEnabled = false // 设置默认定位按钮是否显示，非必需设置。
        aMap.isMyLocationEnabled = true // 设置为true表示启动显示定位蓝点，false表示隐藏定位蓝点并不进行定位，默认是false。
        //设置希望展示的地图缩放级别 https://lbs.amap.com/api/android-sdk/guide/interaction-with-map/method-interaction/?sug_index=0
        // 地图的缩放级别一共分为 17 级，从 3 到 19。数字越大，展示的图面信息越精细。
        val cameraUpdate: CameraUpdate = CameraUpdateFactory.zoomTo(16f)
        // 带有移动过程的动画
        aMap.animateCamera(cameraUpdate)
        // 回调方法获取经纬度信息
        aMap.setOnMyLocationChangeListener { location ->
            val latLng = LatLng(location.latitude, location.longitude)
            if (followMove) {
                aMap.animateCamera(CameraUpdateFactory.newLatLng(latLng))
            }
            //从location对象中获取经纬度信息，地址描述信息，建议拿到位置之后调用逆地理编码接口获取（获取地址描述数据章节有介绍）
//            LogUtils.d(" 获取定位位置:{$location.longitude, ${location.latitude}}")
            if (location.latitude == 0.0 && location.longitude == 0.0) {
//                showMessage("暂未获取到位置信息")
                LogUtils.e("暂未获取到位置信息")
                return@setOnMyLocationChangeListener
            }
            curLatLng = LatLng(location.latitude, location.longitude)
        }
    }

    override fun onTouch(p0: MotionEvent?) {
        if (followMove) {
            //用户拖动地图后，不再跟随移动，需要跟随移动时再把这个改成true
            followMove = false
        }
    }


    /**
     * 申请权限
     */
    @SuppressLint("CheckResult")
    private fun requestPermission() {
        val permissions = listOf(
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.READ_PHONE_STATE,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.ACCESS_COARSE_LOCATION
        )
        PermissionX.init(this)
            .permissions(permissions)
            .onExplainRequestReason { scope, deniedList ->
                val message = "PermissionX需要您同意以下权限才能正常使用"
                scope.showRequestReasonDialog(deniedList, message, "确定", "取消")
            }
            .request { allGranted, grantedList, deniedList ->
                if (allGranted) {
                    locate()
                } else {
                    showMessage("您拒绝了如下权限：$deniedList")
                }
            }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == CommonEditActivity.RC_LIB_MANAGE && resultCode == RESULT_OK) {
            getAll()
        }
    }

}